/*
尽可能还原 Promise 中的每一个 API, 并通过注释的方式描述思路和原理.
*/

// 定义状态常量3
const PENDING = 'pending';
const FULFILLED = 'fulfilled';
const REJECTED = 'rejected';

// Promise原理
class MyPromise {
    constructor (executor) {
        try {
            // 立即执行执行器
            executor(this.resolve, this.reject)
        } catch (error) {
            this.reject(error)
        }
    }
    // 默认状态为pending
    _status = PENDING;
    // 定义存储成功返回值的成员
    _result = undefined;
    // 定义存储失败返回值的成员
    _error = undefined;
    // 成功回调
    _successCallbackArray = [];
    // 失败回调
    _failCallbackArray = [];
    resolve =  (result) => {
        // 只有在状态为pending的情况下才可以更改状态，否则阻止程序继续执行
        if (this._status !== PENDING) return
        // 改变状态为成功
        this._status = FULFILLED;
        // 将成功返回值进行存储
        this._result = result;
        // 如果成功回调存在就执行
        // this._successCallback && this._successCallback(this._result);
        while (this._successCallbackArray.length > 0) this._successCallbackArray.shift()()
    }
    reject =  (error) => {
        // 只有在状态为pending的情况下才可以更改状态，否则阻止程序继续执行
        if (this._status !== PENDING) return
        // 改变状态为失败
        this._status = REJECTED;
        // 将失败返回值进行存储
        this._error = error;
        // 如果失败回调存在就执行
        // this._failCallback && this._failCallback(this._error);
        while (this._failCallbackArray.length > 0) this._failCallbackArray.shift()()
    }
    then (successCallback, failCallback) {
        // successCallback, failCallback为可选参数
        successCallback = successCallback ? successCallback : value => value
        failCallback = failCallback ? failCallback : error => error
        //then始终返回Promise
        let nextPromise = new MyPromise((resolve, reject) => {
            if (this._status === FULFILLED) {
                // 变成异步代码
                setTimeout(() => {
                    try {
                        // 状态为成功执行successCallback,且将成功返回值以参数形式传递给成功回调函数（successCallback）
                        // 将成功回调的返回值赋值给下一个promise
                        let successCallbackResult = successCallback(this._result)
                        // 判断successCallbackResult是普通值，还是promise对象
                        // 如果是普通值，直接resolve
                        // 如果是promise对象，查看promise对象的返回结果
                        // 再根据返回结果决定调用resolve 还是 reject
                        // resolvePromise
                        resolvePromise(nextPromise, successCallbackResult, resolve, reject)
                    } catch (error) {
                        reject(error)
                    }
                }, 0);
            } else if (this._status === REJECTED) {
                setTimeout(() => {
                    try {
                        // 状态为失败执行failCallback,且将失败返回值以参数形式传递给的失败回调函数（failCallback）
                        // 将失败回调的返回值传参给then的promise
                        // failCallback(this._error)
                        let failCallbackResult = failCallback(this._error)
                        resolvePromise(nextPromise, failCallbackResult, resolve, reject)
                    } catch (error) {
                        reject(error)
                    }
                }, 0);
            } else {
                // 状态为等待
                // 将成功回调和失败回调存储起来
                // this._successCallback = successCallback;
                // this._failCallback = failCallback;
                this._successCallbackArray.push(() => {
                    setTimeout(() => {
                        try {
                            let successCallbackResult = successCallback(this._result)
                            resolvePromise(nextPromise, successCallbackResult, resolve, reject)
                        } catch (error) {
                            reject(error)
                        }
                    }, 0);
                })
                this._failCallbackArray.push(() => {
                    setTimeout(() => {
                        try {
                            let failCallbackResult = failCallback(this._error)
                            resolvePromise(nextPromise, failCallbackResult, resolve, reject)
                        } catch (error) {
                            reject(error)
                        }
                    }, 0);
                })
            }
        });
        return nextPromise;
    }
    static all (array) {
        let results = [];
        let i = 0;
        return new MyPromise((resolve, reject) => {
            // 将结果存储在results中，通过i的计数来确保全部任务（尤其是异步任务）执行完毕之后再进行全部的返回
            function addData(key, value) {
                results[key] = value;
                i++;
                if (i === array.length) {
                    resolve(results)
                }
            }
            for (let index = 0; index < array.length; index++) {
                const item = array[index];
                if (item instanceof MyPromise) {
                    // promise
                    item.then(value => {
                        addData(index, value)
                    }, error => {
                        reject(error)
                    });
                } else {
                    // 普通值
                    addData(index, item)
                }
            }
        });
    }
    // 把值包装成promise：是promise直接返回，不是的话实例化一个，并resolve这个值
    static resolve(value) {
        if (value instanceof MyPromise) return value
        return new MyPromise((resolve, reject) => {
            resolve(value)
        });
    }
    // 
    finally(callback) {
        return this.then((value)=> {
            return MyPromise.resolve(callback()).then(() => {
                return value
            })
        }, (error)=> {
            callback();
            throw error;
        })
    }
    // 最终状态失败
    catch(failCallback) {
        return this.then(undefined, failCallback)
    }
}
function resolvePromise(nextPromise, res, resolve, reject) {
    // then回调函数中返回的Promise不能等于then本身返回的Promise，否则报错
    if (nextPromise === res) {
        return reject(new TypeError('Chaining cycle detected for promise #<Promise>'))
    }
    if (res instanceof MyPromise) {
        // promise
        res.then(resolve, reject)
    } else {
        // 普通值
        resolve(res)
    }
}
function dealCallback(nextPromise, callback, value, resolve, reject) {
    setTimeout(() => {
        try {
            let callbackResult = callback(value)
            // 判断回调函数的返回值是普通值，还是promise对象
            // 如果是普通值，直接resolve
            // 如果是promise对象，查看promise对象的返回结果
            // 再根据返回结果决定调用resolve 还是 reject
            // resolvePromise
            resolvePromise(nextPromise, callbackResult, resolve, reject)
        } catch (error) {
            reject(error)
        }
    }, 0);
}
module.exports = MyPromise;